﻿module mirsound;

import std.datetime, std.math;
import std.string, std.stream;

import mirshare;
import share.types, share.protocol, share.utility;

import allegro5.allegro;
import allegro5.allegro_audio;
import allegro5.allegro_acodec;


const wav_base = "Sound/";
const bgm_base = "Sound/";

const bmg_intro = bgm_base ~ "Opening.wav";
const bmg_select = bgm_base ~ "SelChr.ogg";
const bmg_field = bgm_base ~ "Field2.wav";
const bmg_gameover = bgm_base ~ "game-over2.wav";
const bmg_zanarkand = bgm_base ~ "zanarkand.ogg";

const bmg_job_war_m_sel = bgm_base ~ "JMMSel.wav";
const bmg_job_war_wm_sel = bgm_base ~ "JWMSel.wav";
const bmg_job_tao_m_sel = bgm_base ~ "DMMSel.wav";
const bmg_job_tao_wm_sel = bgm_base ~ "DWMSel.wav";
const bmg_job_sor_m_sel = bgm_base ~ "SMMSel.wav";
const bmg_job_sor_wm_sel = bgm_base ~ "SWMSel.wav";

const s_walk_ground_l = 1;
const s_walk_ground_r = 2;
const s_run_ground_l = 3;
const s_run_ground_r = 4;
const s_walk_stone_l = 5;
const s_walk_stone_r = 6;
const s_run_stone_l = 7;
const s_run_stone_r = 8;
const s_walk_lawn_l = 9;
const s_walk_lawn_r = 10;
const s_run_lawn_l = 11;
const s_run_lawn_r = 12;
const s_walk_rough_l = 13;
const s_walk_rough_r = 14;
const s_run_rough_l = 15;
const s_run_rough_r = 16;
const s_walk_wood_l = 17;
const s_walk_wood_r = 18;
const s_run_wood_l = 19;
const s_run_wood_r = 20;
const s_walk_cave_l = 21;
const s_walk_cave_r = 22;
const s_run_cave_l = 23;
const s_run_cave_r = 24;
const s_walk_room_l = 25;
const s_walk_room_r = 26;
const s_run_room_l = 27;
const s_run_room_r = 28;
const s_walk_water_l = 29;
const s_walk_water_r = 30;
const s_run_water_l = 31;
const s_run_water_r = 32;


const s_hit_short = 50;
const s_hit_wooden = 51;
const s_hit_sword = 52;
const s_hit_do = 53;
const s_hit_axe = 54;
const s_hit_club = 55;
const s_hit_long = 56;
const s_hit_fist = 57;

const s_struck_short = 60;
const s_struck_wooden = 61;
const s_struck_sword = 62;
const s_struck_do = 63;
const s_struck_axe = 64;
const s_struck_club = 65;

const s_struck_body_sword = 70;
const s_struck_body_axe = 71;
const s_struck_body_longstick = 72;
const s_struck_body_fist = 73;

const s_struck_armor_sword = 80;
const s_struck_armor_axe = 81;
const s_struck_armor_longstick = 82;
const s_struck_armor_fist = 83;

//const s_powerup_man = 80;
//const s_powerup_woman = 81;
//const s_die_man = 82;
//const s_die_woman = 83;
//const s_struck_man = 84;
//const s_struck_woman = 85;
//const s_firehit = 86;

//const s_struck_magic        = 90;
const s_strike_stone = 91;
const s_drop_stonepiece = 92;

const s_rock_door_open = 100;
const s_intro_theme = 102;
const s_meltstone = 101;
const s_main_theme = 102;
const s_norm_button_click = 103;
const s_rock_button_click = 104;
const s_glass_button_click = 105;
const s_money = 106;
const s_eat_drug = 107;
const s_click_drug = 108;
const s_spacemove_out = 109;
const s_spacemove_in = 110;

const s_click_weapon = 111;
const s_click_armor = 112;
const s_click_ring = 113;
const s_click_armring = 114;
const s_click_necklace = 115;
const s_click_helmet = 116;
const s_click_grobes = 117;
const s_itmclick = 118;

const s_deal_additem = 125;
const s_deal_delitem = 126;

const s_yedo_man = 130;
const s_yedo_woman = 131;
const s_longhit = 132;
const s_widehit = 133;
const s_rush_l = 134;
const s_rush_r = 135;
const s_firehit_ready = 136;
const s_firehit = 137;
  // 2003/03/15 ½Å±Ô¹«°ø
const s_crosshit = 140;
const s_twinhit = 141;

const s_man_struck = 138;
const s_wom_struck = 139;
const s_man_die = 144;
const s_wom_die = 145;



const MAX_AMBIANCE_COUNT = 9;

const MAX_KINDS_OF_WAVE = 50;
const MAX_DUPLE_COUNT = 5;
const MAX_LIM_TIME = 60000;


const MAX_MP3_WAR = -1000;
const MAX_MP3_PEACE = -100;

const _PI = 3.1415927f;


struct SoundBuffer
{
    public ALLEGRO_SAMPLE* sample;
    public ALLEGRO_SAMPLE_ID* sample_id;
    public int Id;
    public TickDuration m_dwLastUseTime;
}

align(1) struct WaveListHeader
{
    align(1):
    char Title[40];
    char TargetDir[10];
    uint FieldCount;
    uint ListCount;
}

align(1) struct WaveList
{
    align(1):
    short Id;
    char Location[14];
}

align(1) struct BGMListHeader
{
align(1):
    char Title[40];
    char TargetDir[10];
    uint FieldCount;
    uint ListCount;
}

align(1) struct BGMList
{
align(1):
    char Map[9];
    char Location[14];
}


class SoundManager
{
    private bool m_bPlay;                   // Sound°¡ ³ª¿Íµµ µÅ´Â°Å?
    private bool m_bBGMPlay;                // BGM ÀÌ Play µÇ¾îµµ µÅ´Â°¡?
    private bool m_bAmbiance;               // Ambiance Wave°¡ Play µÇ¾îµµ µÅ´Â°¡?
    private int m_nUseCount;                // »ç¿ë µÅ°í ÀÖ´Â Sound(Wav) Buffer Count

    private ALLEGRO_VOICE* voice;
    private ALLEGRO_MIXER* mixer;
    private SoundBuffer[] m_ppBuffer;       // Object of Sound Buffer
    private SoundBuffer m_CommonWavBuffer;  // Common use Wave Buffer
    private bool m_bIsWarMode;

    private WaveList[] m_ppWavList;
    private BGMList[] m_ppBGMList;

    //public SoundBuffer m_pMp3;                // Object of BGM(Mp3)
    public ALLEGRO_AUDIO_STREAM* m_pMp3;
    public SoundBuffer[MAX_AMBIANCE_COUNT] m_pAmbianceBuffer;       // Only Ambiance's Buffer
    public bool m_bRunningTimer;
    public float m_lWavMaxVol;
    public float m_lMp3MaxVol;
    public int m_nAmbienceNum;
    public int m_nAmbianceCount;
    
    
    
    
    public this()
    {
        m_ppWavList = null;
        m_ppBGMList = null;
        m_ppBuffer = null;
        m_bPlay = true;
        m_bBGMPlay = false; // ÀÓ½Ã
        
        mixer = null;
        
        m_ppBuffer = new SoundBuffer[MAX_KINDS_OF_WAVE];
        foreach (int i; 0..MAX_KINDS_OF_WAVE)
            m_ppBuffer[i] = SoundBuffer.init;

        m_CommonWavBuffer = SoundBuffer.init;
    
        m_pMp3 = null;
    
        m_lWavMaxVol = 1.0f;
        m_lMp3MaxVol = 1.0f;
        m_nUseCount = 0;
        m_bRunningTimer = false;
        m_bIsWarMode = false;
    }
    
    public ~this()
    {
        int i;

        if (m_ppWavList !is null)
            m_ppWavList = null;

        if (m_ppBGMList !is null)
            m_ppBGMList = null;

    /*if(m_bAmbiance)
    {
        KillTimer(g_xMainWnd.GetSafehWnd(),ID_AMBIANCE_TIMER);
        for(i = 0 ; i < MAX_AMBIANCE_COUNT ; i++)
        {
            m_pAmbianceBuffer[i]->Release();
            m_pAmbianceBuffer[i] = null;
        }
    }
    m_CommonWavBuffer.Release();*/

        if (m_ppBuffer !is null)
        {
            for (i = 0; i < m_nUseCount; i++)           // Buffer Class
            {
                al_destroy_sample(m_ppBuffer[i].sample);
                destroy(m_ppBuffer[i]);
            }
            m_ppBuffer = null;
        }

        //if(m_pWavListHeader != NULL)  delete m_pWavListHeader;
        //if (m_pMp3 !is null) delete m_pMp3;
        //if(m_pSound!=NULL)        delete m_pSound;    // Sound Class
        if (mixer !is null)
        {
            if (al_get_mixer_attached(mixer))
                al_detach_mixer(mixer);
            
            al_destroy_mixer(mixer);
            mixer = null;
        }
        
        if (voice !is null)
        {
            //if (al_get_voice_attached(voice))
            al_detach_voice(voice);

            al_destroy_voice(voice);
            voice = null;
        }
    }
    
    private int ReadWavFileList(in string flname)
    {
        int i, n, count;
        size_t blocksize;
        File reader;
        WaveListHeader header;
        WaveList wav;
    
        if (std.file.exists(flname) == false)
            return -1;
        
        reader = new File;
        scope(exit) { destroy(reader); }
        
        reader.open(flname, FileMode.In);
        if ( reader.isOpen() == false )
            return -1;

        // Header Reading
        reader.readBlock(&header, header.sizeof);
        //m_ppWavList.length = header.FieldCount;
        
        // List Reading
        count = 0;
        for ( i = 0; i < header.ListCount; i++ )
        {
            blocksize = reader.readBlock(&wav, wav.sizeof);

            if (reader.eof())
                break;

            if (blocksize != wav.sizeof)
                break;

            if ( wav.Id != 0 ) 
            {
                n = std.algorithm.countUntil(wav.Location.idup, '\0');
                if (n >= 0)
                    wav.Location[n] = '\0';

                m_ppWavList ~= wav;
                count++;
            }
        }
        reader.close();
        
        return count;
    }

    private int ReadBGMFileList(in string flname)
    {
        int i, n, count;
        char tag;
        size_t blocksize;
        File reader;
        BGMListHeader header;
        BGMList bgm;

        if (std.file.exists(flname) == false)
            return -1;
        
        reader = new File;
        scope(exit) { destroy(reader); }
        
        reader.open(flname, FileMode.In);
        if ( reader.isOpen() == false )
            return -1;

        // Header Reading
        reader.readBlock(&header, header.sizeof);
        //m_ppBGMList.length = header.FieldCount;

        //
        // List Reading
        count = 0;

        //ulong size = reader.size();
        for ( i = 0; i < header.ListCount; )
        {
            blocksize = reader.readBlock(&tag, tag.sizeof);

            if (reader.eof())
                break;

            if ( tag == '[' ) 
            {
                blocksize = reader.readBlock(&bgm, bgm.sizeof);

                if (blocksize != bgm.sizeof)
                    break;

                n = std.algorithm.countUntil(bgm.Location.idup, '\0');
                if (n >= 0)
                    bgm.Location[n] = '\0';

                n = std.algorithm.countUntil(bgm.Map.idup, '\0');
                if (n >= 0)
                    bgm.Map[n] = '\0';

                m_ppBGMList ~= bgm;
                count++;
                i++;
            }
        }
        reader.close();
        
        return count;
    }

    //BOOL      ChgPlayingSet(INT nWavIdx,INT nBufferIdx,INT Sx,INT Sy,INT Dx,INT Dy);
    public bool FreeNotUseBuffer()
    {
        TickDuration dwCurrentTime;
        TickDuration dwTempTime;
        SoundBuffer pxTempBuffer;
        int i = 0;

        dwCurrentTime = Clock.currSystemTick();     // ÇöÀç ½Ã°£À» ±¸ÇÑ´Ù.

        do
        {
            dwTempTime = m_ppBuffer[i].m_dwLastUseTime;
            if (dwTempTime.msecs != 0)
            {
                dwTempTime = dwCurrentTime - dwTempTime;
                if (dwTempTime.msecs > MAX_LIM_TIME)    // 1ºÐ ÀÌ»ó ¾È¾´°ÍÀ» ³¯·Á¶ó
                {   
                    al_destroy_sample(m_ppBuffer[i].sample);
                    pxTempBuffer = m_ppBuffer[i];
                    m_nUseCount--;
                    for(int j = i; j < m_nUseCount; j++)
                    {
                        m_ppBuffer[j] = m_ppBuffer[j + 1];
                    }
                    m_ppBuffer[m_nUseCount] = pxTempBuffer;
                    i--;
                }
                i++;
            }
        }
        while(i < m_nUseCount);
        
        return false;
    }
    
    public bool InitMirSound()
    {
        int total = MAX_AMBIANCE_COUNT + MAX_KINDS_OF_WAVE;

        voice = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH.ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF.ALLEGRO_CHANNEL_CONF_2);
        if (voice is null)
            return false;
        
        //mixer = al_get_default_mixer();
        mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH.ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF.ALLEGRO_CHANNEL_CONF_2);
        if (mixer is null)
            return false;
        
        if (!al_attach_mixer_to_voice(mixer, voice))
            return false;
        
        m_bBGMPlay = true;
        
        if (al_reserve_samples(total))
        {
            if (ReadWavFileList("./SoundList.wwl") < 0)
                return false;

            if (ReadBGMFileList("./BgmList.wwl") < 0)
                return false;
        }
            
        return true;
    }
    
    public SoundBuffer* FindBuffer(int wavnum, bool loadwav = true)
    {
        if (m_nUseCount > 0)
        {
            //for(int i = 0 ; i < MAX_KINDS_OF_WAVE; i++)
            foreach(int i; 0..MAX_KINDS_OF_WAVE)
            {
                if (m_ppBuffer[i].Id == wavnum) // ÀÐ¾î ³õÀº °ÍµéÁß¿¡ ÀÖ³Ä?
                {
                    return &m_ppBuffer[i];
                }
            }
        }
        
        // ÀÐ¾î ³õÀº°ÍÁß¿¡ ¾ø´Ü¸»ÀÌ³Ä?
        if (loadwav)
        {
            if (m_nUseCount < MAX_KINDS_OF_WAVE)
            {
                // ±×·³ ÀÐÀÚ!
                string flname = wav_base ~ SeekSoundName(wavnum);
                
                ALLEGRO_SAMPLE *sample = al_load_sample( flname.toStringz );
                //if(m_3DEnable) m_ppBuffer[m_nUseCount]->Enable3d(); // TODO:
                if (sample !is null)
                {
                    m_ppBuffer[m_nUseCount].sample = sample;
                    m_ppBuffer[m_nUseCount].Id = wavnum;
                    m_nUseCount++;
                    return &m_ppBuffer[m_nUseCount-1];
                }
            }
        }
        
        // Çä! ÀÐÀ» °ø°£ ¸¶Àú ¾ø´Ü ¸»ÀÌ³Ä?
        // ±×·³ ¸»ÀÚ!
        return null;
    }
    
    //CSound*       GetSoundObject(VOID){return m_pSound;}

    public void StopAllSound()
    {
        for (int i = 0; i < m_nUseCount; i++)
        {
            if (m_ppBuffer[i].sample_id !is null)
                al_stop_sample(m_ppBuffer[i].sample_id);
        }
    }
    
    public void StopSound(int wavnum)
    {
        SoundBuffer* buffer = FindBuffer(wavnum, false);
        if (buffer !is null)
            if (buffer.sample_id !is null)
                al_stop_sample(buffer.sample_id);
    }
    
    public void StopSound(int nNum, int BufIdx)
    {
        // TODO: BufIdx ???
    }

    public void PlayAmbianceWav(int wavnum)
    {
        if (m_bAmbiance)
        {
            FreeNotUseBuffer();
            
            if (m_pAmbianceBuffer[wavnum].sample_id !is null)
                al_stop_sample(m_pAmbianceBuffer[wavnum].sample_id);
            
            al_play_sample(m_pAmbianceBuffer[wavnum].sample, m_lWavMaxVol, 0.0, 1.0, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_ONCE, m_pAmbianceBuffer[wavnum].sample_id);
        }
    }
    
    public void StopBGM()
    {
        if (m_pMp3 !is null)
        {
            al_drain_audio_stream(m_pMp3);
            al_set_audio_stream_playing(m_pMp3, false);
            
            if (al_get_audio_stream_attached(m_pMp3))
                al_detach_audio_stream(m_pMp3);
            al_destroy_audio_stream(m_pMp3);
            m_pMp3 = null;
        }
    }
    
    public void PlayBGM(string mapname, bool loop = true)
    {
        if (m_bBGMPlay)
        {
            StopBGM();

            string flname = bgm_base ~ SeekBGMName(mapname);

            // TODO: Allegro5 can't support mp3 so convert those extensions to .ogg
            flname = std.array.replace(flname, ".MP3", ".ogg");
            
            if (flname.length > 0 && std.file.exists(flname))
            {
                //m_pMp3.m_dwLastUseTime = Clock.currSystemTick(); // PDS:
                m_pMp3 = al_load_audio_stream( flname.toStringz, 4, 8192 );
                
                if (m_pMp3 !is null)
                {
                    if (loop)
                        al_set_audio_stream_playmode(m_pMp3, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_LOOP);
                    else
                        al_set_audio_stream_playmode(m_pMp3, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_ONCE);
                    
                    al_set_audio_stream_gain(m_pMp3, 1.0f);
                    al_attach_audio_stream_to_mixer(m_pMp3, mixer);
                }
            }
        }
    }

    public void PlayBGMEx(string bgmname, /*int bgmnum,*/ bool loop = true)
    {
        if (m_bBGMPlay)
        {
            StopBGM();
            
            //      FindBGMFileName(bgmnum, true);
            
            if (bgmname.length > 0 && std.file.exists(bgmname))
            {
                //m_pMp3.m_dwLastUseTime = Clock.currSystemTick(); // PDS:
                m_pMp3 = al_load_audio_stream( bgmname.toStringz, 2, 1024 * 4 );
                
                if (m_pMp3 !is null)
                {
                    if (loop)
                        al_set_audio_stream_playmode(m_pMp3, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_LOOP);
                    else
                        al_set_audio_stream_playmode(m_pMp3, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_ONCE);
                    
                    al_set_audio_stream_gain(m_pMp3, 1.0f);
                    al_attach_audio_stream_to_mixer(m_pMp3, mixer);
                }
            }
        }
    }
    
    //void      PlayMagicEffect(POINT Target,POINT Chr,int Wavnum);

    public int PlaySoundEx(string bgmname, float lVolume = 1.0f, bool loop = false)
    {
        if (m_bPlay)
        {
            FreeNotUseBuffer();

            SoundBuffer* buffer = null;
            if (m_nUseCount < MAX_KINDS_OF_WAVE)
            {
                auto sample = al_load_sample( bgmname.toStringz );
                //if(m_3DEnable) m_ppBuffer[m_nUseCount]->Enable3d(); // TODO:
                if (sample !is null)
                {
                    m_ppBuffer[m_nUseCount].sample = sample;
                    m_ppBuffer[m_nUseCount].Id = -1;
                    m_nUseCount++;
                    buffer = &m_ppBuffer[m_nUseCount-1];
                }
            }
            //SoundBuffer* buffer = FindBuffer(wavnum, true);
            if (buffer !is null)
            {
                buffer.m_dwLastUseTime = Clock.currSystemTick();
                if (loop)
                    al_play_sample(buffer.sample, lVolume, 0.0, 1.0, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_LOOP, buffer.sample_id);
                else
                    al_play_sample(buffer.sample, lVolume, 0.0, 1.0, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_ONCE, buffer.sample_id);
                
                //return buffer.nBufferIdx;
            }
        }
        
        return MAX_DUPLE_COUNT;
    }
    
    public int PlaySound(int wavnum, float lVolume = 1.0f, bool loop = false)
    {
        if (m_bPlay)
        {
            FreeNotUseBuffer();

            SoundBuffer* buffer = FindBuffer(wavnum, true);
            if (buffer !is null)
            {
                buffer.m_dwLastUseTime = Clock.currSystemTick();
                if (loop)
                    al_play_sample(buffer.sample, lVolume, 0.0, 1.0, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_LOOP, buffer.sample_id);
                else
                    al_play_sample(buffer.sample, lVolume, 0.0, 1.0, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_ONCE, buffer.sample_id);

                //return buffer.nBufferIdx;
            }
        }
        
        return MAX_DUPLE_COUNT;
    }
    
    // lVolume = 100% ~ 1% 
    public int PlayActorWav(int sx, int sy, int dx, int dy, int wavnum, float volume = 1.0f, bool loop = false)
    {
        IntPoint Mon, Chr;
        int distance, direction;
        
        Mon.set(sx, sy);
        Chr.set(dx, sy); // TODO: should sy be dy?
        
        if (m_bPlay)
        {
            FreeNotUseBuffer();

            SoundBuffer* buffer = FindBuffer(wavnum, true);
            if (buffer !is null)
            {
                distance = CalsDistance(Mon, Chr);
                direction = CalsDirection(Mon, Chr);
                
                buffer.m_dwLastUseTime = Clock.currSystemTick();
                if (loop)
                {
                    // 2D pan
                    al_play_sample(buffer.sample, CalsVolume(distance), CalsPan(direction, distance), 1.0, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_LOOP, buffer.sample_id);                                           // 2D pan
                }
                else
                {
                    // 2D pan
                    volume = CalsVolume(distance)*((100-volume==0)?1:(100-volume)/5);
                    al_play_sample(buffer.sample, volume, CalsPan(direction, distance), 1.0, ALLEGRO_PLAYMODE.ALLEGRO_PLAYMODE_ONCE, buffer.sample_id);
                }
                //return buffer.nBufferIdx;
            }
        }
        
        return MAX_DUPLE_COUNT;
    }
    
    public void ItemClickSound(const StandardItem std)
    {
        switch (std.StdMode)
        {
            case 0: PlaySound(s_click_drug); break;
            case 5, 6: PlaySound(s_click_weapon); break;
            case 10, 11: PlaySound(s_click_armor); break;
            case 22, 23: PlaySound(s_click_ring); break;
            case 24, 26:
            {
                if ((std.Name.indexOf("Àå°©") > -1) || (std.Name.indexOf("°©¹Ú") > -1))
                    PlaySound(s_click_grobes);
                else
                    PlaySound(s_click_armring);
                 break;
            }
            case 19, 20, 21: PlaySound(s_click_necklace); break;
            case 15: PlaySound(s_click_helmet); break;
            default: PlaySound(s_itmclick); break;
        }
    }

    public void ItemUseSound(int stdmode)
    {
        switch (stdmode)
        {
            case 0: PlaySound(s_click_drug); break;
            case 1, 2: PlaySound(s_eat_drug); break;
            default: break;
        }
    }







    private string SeekSoundName(int wavnum)
    {
        if (m_bPlay)
        {
            for (int i = 0; i < m_ppWavList.length; i++)
            {
                if (wavnum == m_ppWavList[i].Id) 
                    return m_ppWavList[i].Location.idup;
            }
        }
        
        return null;
    }

    private string SeekBGMName(in string mapname)
    {
        if (m_bBGMPlay)
        {
            for (int i = 0; i < m_ppBGMList.length; i++)
            {
                if (CompareLStr(mapname, m_ppBGMList[i].Map.idup, mapname.length))
                    return m_ppBGMList[i].Location.idup;
            }
        }
        
        return null;
    }
    
    //private void      ReadWavFileList(char* fName);+/
    
    private float CalsVolume(int distance)
    {
        float l_Result;
        if (distance != 0)
        {
            l_Result = ((cos(_PI*(distance / 26.0f))) * 100);
            l_Result = (101 - l_Result);        // ÃÖ´ë º¼·ë 0 ÃÖ¼Ò º¼·ý (-1)*x : ÇöÁ¦ÀÇ 100-(x)%
            l_Result = m_lWavMaxVol + l_Result * (-20);         // ÃÖ¼ÒÀ½·® -2000 ~ ÃÖ´ëÀ½·® 0
            return l_Result;
        }
        else
        {
            return m_lWavMaxVol;                            // °ãÃÄ Á® ÀÖ°Å³ª º»ÀÎÀÇ ¼Ò¸®   ÃÖ´ë À½·®À¸·Î
        }
    }
    
    private int CalsPan(int direction, int distance)
    {
        int pans;
        pans = direction * cast(int)(5000.0f*(sin(_PI*(distance / 26.0f))));

        return pans;
    }
    
    private float CalsDistanceX(IntPoint Src, IntPoint Chr)
    {
        float l_Result;
        l_Result = cast(float)((Chr.getX() - Src.getX()) % 13);                       // °Å¸®´Â 12 ÀÌ»óÀÏ¼ö ¾ø´Ù.
        l_Result = cast(float)(1.0f-sqrt(1.0f - l_Result/12.0f))*(-1.0f);
        return l_Result;
    }
    
    private float CalsDistanceY(IntPoint Src, IntPoint Chr)
    {
        float l_Result;
        l_Result = cast(float)((Chr.getY() - Src.getY())%13);                      // °Å¸®´Â 12 ÀÌ»óÀÏ¼ö ¾ø´Ù.
        l_Result = cast(float)(1.0f-sqrt(1.0f - (l_Result)/12.0f))*(-1.0f);
        return l_Result;
    }
    
    private int CalsDistance(IntPoint Src, IntPoint Chr)
    {
        int Cx,Cy;
        int nResult;
        Cx = Src.getX() - Chr.getX();
        Cy = Src.getY() - Chr.getY();
        Cx = Cx<0 ? Cx*(-1) : Cx;
        Cy = Cy<0 ? Cy*(-1) : Cy;
        
        nResult = Cx >Cy ? Cx : Cy;
        return nResult;
    }
    
    private int CalsDirection(IntPoint Src, IntPoint Chr)
    {
        return (Src.getX() > Chr.getX()) ? 1 : (Src.getX() < Chr.getX()) ? -1 : 0;
    }
}

